package com.ruoyi.business.youdaoController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.business.services.HttpService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.SaveType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.EncrypDES;
import com.ruoyi.common.utils.GetUrlParam;
import com.ruoyi.common.utils.OtherUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.domain.vo.R;
import com.ruoyi.system.protocol.IDynamicSearchService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("ownDouYinApi")
public class DouYinController {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private HttpService httpService;
    @Autowired
    private IDynamicSearchService dynamicSearchService;

    private final static String CLASSESEN = "youdao";




    private final static String CALLBACK_URLBASE = "http://c2.wkanx.com/tracking";


    /**
     * @return
     * @throws Exception
     */
    @Log(title = "有道", businessType = BusinessType.ESCALATION, esIndex = "youdao_log", saveType = SaveType.ES)
    @RequestMapping("/send")
    public Object send(HttpServletRequest request) throws Exception {
        String queryString = request.getQueryString();
        String channelId = request.getParameter("channelId");
        String dmpid = request.getParameter("dmpid");
        if(StringUtils.isBlank(channelId) || "null".equals(channelId)){
            return R.failure().msg("channelId不能为空");
        }
        if(StringUtils.isBlank(dmpid) || "null".equals(dmpid)){
            return R.failure().msg("dmpid不能为空");
        }

        Map<String, Object> baseParamsMap = GetUrlParam.queryStrToMap(queryString);

        baseParamsMap.remove("channelId");
        baseParamsMap.remove("dmpid");

        if("6527528662665216".equals(channelId)){
            //抖音链接配置错误，配置到yy渠道上了。现在做判断修改回来
            channelId = "6546046257629184";
            redisCache.setCacheObject(dmpid+"_ChannelIDMapping", channelId);
        }

        Boolean dmpIdBool = getDmpId(channelId, dmpid);
        if (dmpIdBool) {
            return R.failure().msg("dmpid已存在");
        }


        Map<String, Object> channelDetail = redisCache.getCacheMapValue(CLASSESEN+"Cache", channelId);
        if(channelDetail == null){
            return R.failure().msg("channelId不正确");
        }
        String url = channelDetail.get("request_address") + "";
        String requestType = channelDetail.get("request_type") + "";
        String requestAddress = GetUrlParam.getRequestAddress(url);
        String staticParameters = GetUrlParam.TruncateUrlPage(url);
        Map<String, Object> staticParamsMap = GetUrlParam.queryStrToMap(staticParameters);
        baseParamsMap.putAll(staticParamsMap);


        String ua = baseParamsMap.get("ua") + "";
        String ip = baseParamsMap.get("ip") + "";
        if(StringUtils.isNotBlank(ua) && !"null".equals(ua)){
        }else{
            //request 获取 ua
            ua = request.getHeader("User-Agent");
            baseParamsMap.put("ua", URLEncoder.encode(ua, Constants.UTF8));
        }
        if(StringUtils.isNotBlank(ip) && !"null".equals(ip)){
        }else{
            //request 获取 ip
            ip = IpUtils.getIpAddr(request);
            baseParamsMap.put("ip", ip);
        }

        String callbackClientId = channelDetail.get("callback_clientid") + "";
        String callbackSecretkey = channelDetail.get("callback_secretkey") + "";

        String idfaMd5 = getMapValue(baseParamsMap, "idfa_md5");
        String os = getMapValue(baseParamsMap, "os");
        String oaid = getMapValue(baseParamsMap, "oaid");
        String imei = getMapValue(baseParamsMap, "imei");
        LinkedHashMap<String, String> callbackMap = new LinkedHashMap<>();
        callbackMap.put("cid", getMapValue(baseParamsMap, "cid"));
        callbackMap.put("clientid", callbackClientId);
        callbackMap.put("clientkey", callbackSecretkey);
        callbackMap.put("idfa", idfaMd5);
        //下游没有imei, 但是有imei_md5
        callbackMap.put("imei", imei);
        //下游的mac是进行MD5加密过的就是上游的mac_md5
        callbackMap.put("mac", getMapValue(baseParamsMap, "mac"));
        callbackMap.put("os", os);
        //sid代表请求标识
        callbackMap.put("sid", dmpid);
        //stime为上报时间戳。 上传过来的参数为ts
        callbackMap.put("stime", getMapValue(baseParamsMap, "ts"));
        callbackMap.put("conv_action", "__EVENT__");

        List<String> tempList = new ArrayList<>();
        for(String key: callbackMap.keySet()){
            tempList.add(key+"="+callbackMap.get(key));
        }
        String callbackParams = String.join("&", tempList);
        EncrypDES encrypDES = new EncrypDES();
        String callbackBase = OtherUtils.getServerUrl(request) + "ownDouYinApi/callback/"+channelId+"/"+dmpid+"/";
        String encrypt_u = encrypDES.encrypt(CALLBACK_URLBASE);
        String nu = callbackBase + encrypt_u + "?"+callbackParams;
        //nu 必须以https开头
        nu = nu.replace("http://", "https://");

        //抖音回调地址取得参数是callback
        baseParamsMap.put("callback", URLEncoder.encode(nu, Constants.UTF8));


        supplementParams(baseParamsMap, dmpid);


        tempList = new ArrayList<>();
        for(String key: baseParamsMap.keySet()){
            tempList.add(key+"="+baseParamsMap.get(key));
        }
        String requestParameters = String.join("&", tempList);


        String uuid = IdUtils.fastSimpleUUID();
        String reqType = "click";
        long l = System.currentTimeMillis();
        if("POST".equals(requestType)){
            httpService.sendPost(requestAddress, requestParameters, ip, ua, uuid, reqType);
        }else{
            httpService.sendGet(requestAddress, requestParameters, ip, ua, uuid, reqType);
        }
        System.out.println("请求耗时: " + (System.currentTimeMillis() - l) + "ms");

        redisCache.setCacheMapValue(dmpid+"_Cache", "requestAddress", requestAddress);
        redisCache.setCacheMapValue(dmpid+"_Cache", "requestParameters", requestParameters);
        redisCache.setCacheMapValue(dmpid+"_Cache", "reqResultId", uuid);


        return R.success();
    }

    /**
     * 补充wifi上报抖音参数
     * @param baseParamsMap
     */
    private static void supplementParams(Map<String, Object> baseParamsMap, String dmpid) {
        //ios以idfa_md5为准。 Android以imei_md5和oaid为准。 wifi中 imei就是imei_md5
        baseParamsMap.put("androidid_md5", "");
        baseParamsMap.put("androidid", "");
        baseParamsMap.put("caid", "");
        baseParamsMap.put("click_id", dmpid);
        baseParamsMap.put("idfa", "");
        baseParamsMap.put("imei_md5", getMapValue(baseParamsMap, "imei"));
        baseParamsMap.put("imei", "");
        baseParamsMap.put("impression_id", IdUtils.fastSimpleUUID());
        baseParamsMap.put("ipv6", "");
        baseParamsMap.put("model", ""); //5G
        baseParamsMap.put("oaid_md5", "");
        baseParamsMap.put("os_version", ""); //11
        String os = getMapValue(baseParamsMap, "os");
        if ("0".equals(os)) {
            baseParamsMap.put("os", "android");
        } else if ("1".equals(os)) {
            baseParamsMap.put("os", "ios");
        }
        baseParamsMap.put("request_id", dmpid);
        baseParamsMap.put("timestamp", getMapValue(baseParamsMap, "ts"));
        baseParamsMap.put("union_site", ""); //""


        //wifi比较特殊不校验，所以rta_trace_id 给了  NO_CHECK
        baseParamsMap.put("rta_trace_id", "NO_CHECK");


        //baseParamsMap   如果value是__开头和结尾的设置为空
        for (String key : baseParamsMap.keySet()) {
            String val = baseParamsMap.get(key) + "";
            if (val.startsWith("__") && val.endsWith("__")) {
                baseParamsMap.put(key, "");
            }
        }
    }

    //用于判断今日内dmpid是否已经上报过
    private Boolean getDmpId(String channelId, String dmpid) {
        String date = DateUtils.getDate() + " 00:00:00";
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("businessTypeStr.keyword", "ESCALATION"));
        boolQueryBuilder.must(QueryBuilders.termQuery("params.channelId.keyword", channelId));
        boolQueryBuilder.must(QueryBuilders.termQuery("dmpid.keyword", dmpid));
        boolQueryBuilder.must(new RangeQueryBuilder("createTimeStr.keyword").gte(date).format("yyyy-MM-dd HH:mm:ss"));
        Long youdaoLog = dynamicSearchService.searchCount("youdao_log", null, boolQueryBuilder);
        return youdaoLog > 0;
    }


    private static String getMapValue(Map<String, Object> map, String key){
        if(map == null){
            return "";
        }
        if(map.get(key) == null){
            return "";
        }
        if((map.get(key)+"").startsWith("__")){
            return "";
        }
        return map.get(key)+"";
    }


    @Log(title = "有道", businessType = BusinessType.CALLBACK, esIndex = "youdao_log", saveType = SaveType.ES)
    @RequestMapping("/callback/{channelId}/{dmpid}/{encryptedUrl}")
    public Object send(HttpServletRequest request, @PathVariable("encryptedUrl") String encryptedUrl) throws Exception {
        String queryString = request.getQueryString();
        Map<String, Object> queryMap = GetUrlParam.queryStrToMap(queryString);
//        String eventType = queryMap.get("conv_action") + "";
//        if("android_activate".equals(eventType) || "ios_activate".equals(eventType)){
//            queryMap.put("event_type", 1);
//        }else if("android_register".equals(eventType) || "ios_register".equals(eventType)) {
//            queryMap.put("event_type", 2);
//        }else if("android_purchase".equals(eventType) || "ios_purchase".equals(eventType)) {
//            queryMap.put("event_type", 3);
//        }else if("android_day1retention".equals(eventType) || "ios_day1retention".equals(eventType)) {
//            queryMap.put("event_type", 5);
//        }else if("android_download".equals(eventType) || "android_addtocart".equals(eventType) || "android_credit".equals(eventType) || "android_custom".equals(eventType)
//                || "ios_addtocart".equals(eventType) || "ios_credit".equals(eventType) || "ios_custom".equals(eventType)) {
//            //安卓： 下载、加入购物车、授信、自定义
//            //ios： 加入购物车、授信、自定义
//            queryMap.put("event_type", 6);
//        }else {
//            queryMap.put("event_type", 1);
//        }

        queryMap.put("event_type", 1);


        LinkedHashMap<String, String> callbackMap = new LinkedHashMap<>();
        callbackMap.put("cid", getMapValue(queryMap, "cid"));
        callbackMap.put("clientid", getMapValue(queryMap, "clientid"));
//        callbackMap.put("event_type", getMapValue(queryMap, "event_type"));
        callbackMap.put("idfa", getMapValue(queryMap, "idfa"));
        //下游没有imei, 但是有imei_md5
        callbackMap.put("imei", getMapValue(queryMap, "imei"));
        //下游的mac是进行MD5加密过的就是上游的mac_md5
        callbackMap.put("mac", getMapValue(queryMap, "mac"));
        callbackMap.put("os", getMapValue(queryMap, "os"));
        //sid是下游给的click_id。 代表请求标识
        callbackMap.put("sid", getMapValue(queryMap, "sid"));
        //stime为上报时间戳。 上传过来的参数为ts
        callbackMap.put("stime", getMapValue(queryMap, "stime"));
        //获取当前时间戳 并转化为秒
        callbackMap.put("ts", (System.currentTimeMillis()/1000)+"");

        String callbackSecretkey = getMapValue(queryMap, "clientkey");
        List<String> tempList = new ArrayList<>();
        for(String key: callbackMap.keySet()){
            tempList.add(key+"="+callbackMap.get(key));
        }
        String callbackParams = String.join("&", tempList);
        String md5 = DigestUtils.md5DigestAsHex((callbackParams+callbackSecretkey).getBytes(Constants.UTF8)).toUpperCase();
        callbackParams = callbackParams + "&event_type="+getMapValue(queryMap, "event_type");
        queryString = callbackParams + "&sign="+md5;

        EncrypDES encrypDES = new EncrypDES();
        String requestAddress = encrypDES.decrypt(encryptedUrl);

        String uuid = IdUtils.fastSimpleUUID();
        String reqType = "callback";
        httpService.sendGet(requestAddress, queryString, null, null, uuid, reqType);
        return R.success();
    }

}
